#include "spl.includes.h"
#include "splib.h"

using namespace SPLib;
using namespace SPLib::Windows;
using namespace SPLib::Geom;

const UINT WM_TASKBARCREATED = RegisterWindowMessage(_T("TaskbarCreated"));

#if (_WIN32_WINNT < 0x0601)

#define MSGFLT_RESET    0
#define MSGFLT_ALLOW    1
#define MSGFLT_DISALLOW 2

#endif

#pragma region Messaging
VOID WndBase::wndProc(Event::WndProcEvent& iEvent)
{
  switch(iEvent.msg)
  {
    ////////////////////////////////////////////////////////////////////
    // Window Notifications
  case WM_DESTROY:
    onDestroy();
    break;
#ifndef COMMON_WM_ONLY
  case WM_STYLECHANGED:
    onStyleChanged(Event::StyleEvent(iEvent.wParam, iEvent.lParam));
    break;
  case WM_STYLECHANGING:
    onStyleChanging(Event::StyleEvent(iEvent.wParam, iEvent.lParam));
    break;
#if (WINVER >= 0x0501)
  case WM_THEMECHANGED:
    onThemeChanged();
    break;
#endif
  case WM_USERCHANGED:
    onUserChanged();
    break;
#endif
    ////////////////////////////////////////////////////////////////////
    // Keyboard Notifications
  case WM_HOTKEY:
    onHotKey(Event::HotkeyEvent(iEvent.wParam, iEvent.lParam));
    break;
    ////////////////////////////////////////////////////////////////////
    // Painting & Drawing Notifications
#ifndef COMMON_WM_ONLY
  case WM_DISPLAYCHANGE:
    onDisplayChange(Event::DisplayChangeEvent(iEvent.wParam, iEvent.lParam));
    break;
#endif
    ////////////////////////////////////////////////////////////////////
    // Menu Notifications
  case WM_COMMAND:
    onCommand(Event::CommandEvent(iEvent.wParam, iEvent.lParam));
    break;
    //#if (WINVER >= 0x0600)
    ////////////////////////////////////////////////////////////////////
    // Desktop Window Management Notifications
  case WM_DWMCOMPOSITIONCHANGED:
    onCompositionChanged();
    break;
    //#endif
    ////////////////////////////////////////////////////////////////////
    // Device Management Notifications
  case WM_DEVICECHANGE:
    onDeviceChange(Event::DeviceChangeEvent(iEvent.wParam, iEvent.lParam));
    break;
    ////////////////////////////////////////////////////////////////////
    // Misc Notifications
  case WM_NOTIFYICON:
    onNotifyIcon(Event::NotifyIconEvent(iEvent.wParam, iEvent.lParam));
    break;
  case WM_TIMER:
    onTimer(Event::TimerEvent(iEvent.wParam));
    break;
  default:
    if (iEvent.msg == WM_TASKBARCREATED)
      onTaskbarCreated();
    break;
  }
}

VOID WndBase::initWindow()
{
  HMODULE hUser32;
  typedef BOOL (WINAPI *LPMSGFILTEREX)(HWND, UINT, DWORD, VOID*);
  typedef BOOL (WINAPI *LPMSGFILTER)(UINT, DWORD);

  // get user32.dll module handle
  if (hUser32 = GetModuleHandle(_T("user32.dll")))
  {
    switch (GetVersion())
    {
    case 0x0601:
      {
        // get ChangeWindowMessageFilterEx function in user32.dll
        LPMSGFILTEREX msgFilterEx = (LPMSGFILTEREX)GetProcAddress(
          hUser32, "ChangeWindowMessageFilterEx");

        // if function exists, allow TASKBARCREATED messages
        if (msgFilterEx)
          msgFilterEx(mHandle, WM_TASKBARCREATED, MSGFLT_ALLOW, NULL);
        break;
      }
    case 0x0600:
      {
        // get ChangeWindowMessageFilter function in user32.dll
        LPMSGFILTER msgFilter = (LPMSGFILTER)GetProcAddress(
          hUser32, "ChangeWindowMessageFilter");

        // if function exists, allow TASKBARCREATED messages
        if (msgFilter)
          msgFilter(WM_TASKBARCREATED, MSGFLT_ALLOW);
        break;
      }
    }
  }
}

LRESULT WndBase::defWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  Event::WndProcEvent wEvent = { };

  WndBase *wnd;

  if (msg == WM_NCCREATE)
  {
    LPCREATESTRUCT struc = (LPCREATESTRUCT)lParam;

    wnd = reinterpret_cast<WndBase*>(struc->lpCreateParams);
    wnd->mHandle = hWnd;
    wnd->setUserData(wnd);
  }
  else
  {
    wnd = fromHandle(hWnd);
  }

  if (wnd && hWnd == wnd->mHandle)
  {
    wnd->_wParam    = wParam;
    wnd->_lParam    = lParam;

    wEvent.msg      = msg;
    wEvent.wParam   = wParam;
    wEvent.lParam   = lParam;

    wnd->wndProc(wEvent);
  }

  return wEvent.handled ? wEvent.lResult :
    DefWindowProc(hWnd, msg, wParam, lParam);
}
#pragma endregion

#pragma region Device Management Notifications
VOID WndBase::onDeviceChange(Event::DeviceChangeEvent& iEvent) {}
#pragma endregion

#pragma region Painting & Drawing Notifications
#ifndef COMMON_WM_ONLY
VOID WndBase::onDisplayChange(Event::DisplayChangeEvent& iEvent) {}
#endif
#pragma endregion

#pragma region Keyboard Notifications
VOID WndBase::onHotKey(Event::HotkeyEvent& iEvent) {}
#pragma endregion

#pragma region Menu Notifications
VOID WndBase::onCommand(Event::CommandEvent& iEvent) {}
#pragma endregion

#pragma region Desktop Window Management Notifications
//#if (WINVER >= 0x0600)
VOID WndBase::onCompositionChanged() {}
//#endif
#pragma endregion

#pragma region Window Notifications
VOID WndBase::onDestroy() {}
#pragma endregion

#pragma region Misc Notifications
VOID WndBase::onTimer(Event::TimerEvent& iEvent) {}
#pragma endregion

#pragma region Notify Icon
VOID WndBase::onTaskbarCreated() {}

VOID WndBase::onNotifyIcon(Event::NotifyIconEvent& iEvent) {}
#pragma endregion